// Copyright (C) Kumo inc. and its affiliates.
// Author: Jeff.li lijippy@163.com
// All rights reserved.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <https://www.gnu.org/licenses/>.
//

#include <cantor/transform/stmt.h>
#include <cantor/transform/stmts/type_stmt.h>
#include <cantor/transform/stmts/start_txn_stmt.h>
#include <cantor/transform/stmts/commit_txn_stmt.h>
#include <cantor/transform/stmts/rollback_txn_stmt.h>
#include <cantor/transform/stmts/pragma_set_stmt.h>
#include <cantor/transform/stmts/new_prepare_stmt.h>
#include <cantor/transform/stmts/exec_prepare_stmt.h>
#include <cantor/transform/stmts/dealloc_prepare_stmt.h>
#include <cantor/transform/stmts/kill_stmt.h>
#include <cantor/transform/stmts/create_namespace_stmt.h>
#include <cantor/transform/stmts/drop_namespace_stmt.h>
#include <cantor/transform/stmts/alter_namespace_stmt.h>
#include <cantor/transform/stmts/create_user_stmt.h>
#include <cantor/transform/stmts/drop_user_stmt.h>
#include <cantor/transform/stmts/alter_user_stmt.h>
#include <cantor/transform/stmts/priv_stmt.h>
#include <cantor/transform/stmts/insert_stmt.h>
#include <cantor/transform/stmts/update_stmt.h>
#include <cantor/transform/stmts/truncate_stmt.h>
#include <cantor/transform/stmts/delete_stmt.h>
#include <cantor/transform/stmts/select_stmt.h>
#include <cantor/transform/stmts/union_stmt.h>
#include <cantor/transform/stmts/create_table_stmt.h>
#include <cantor/transform/stmts/drop_table_stmt.h>
#include <cantor/transform/stmts/create_view_stmt.h>
#include <cantor/transform/stmts/drop_view_stmt.h>
#include <cantor/transform/stmts/create_database_stmt.h>
#include <cantor/transform/stmts/drop_database_stmt.h>
#include <cantor/transform/stmts/alter_table_stmt.h>
#include <cantor/transform/stmts/alter_view_stmt.h>
#include <cantor/transform/stmts/explain_stmt.h>
#include <cantor/transform/stmts/load_data_stmt.h>
#include <cantor/transform/stmts/restore_table_stmt.h>
#include <turbo/times/time.h>


namespace cantor::transform {
    void TransStmt::resolve_type_name(const cantor::parser::StmtNode *node) {
        TransTypeStmt trnas;
        auto ptr = (const cantor::parser::TypeStmt*)node;
        trnas.resolve_ast(ptr);
        status = trnas.check();
        if (!status.ok()) {
            return;
        }
        *stmt.mutable_type_stmt() = std::move(trnas.type_stmt);
        stmt.set_type(pb::ast::STMT_TYPE_NAME);
    }
    void TransStmt::resolve_ast(const cantor::parser::StmtNode *node) {
        if (!node) {
            status = turbo::data_loss_error("node is nullptr");
            return;
        }
        switch (node->stmt_type) {
            case pb::ast::STMT_TYPE_NAME:
                resolve_type_name(node);
                return;
            case pb::ast::STMT_START_TRANSACTION: {
                status = TransStartTxnStmt::resolve_to((cantor::parser::StartTxnStmt*)node, stmt.mutable_start_txn_stmt());
                stmt.set_type(pb::ast::STMT_START_TRANSACTION);
                return;
            }
            case pb::ast::STMT_COMMIT_TRANSACTION: {
                status = TransCommitTxnStmt::resolve_to((cantor::parser::CommitTxnStmt*)node, stmt.mutable_commit_txn_stmt());
                stmt.set_type(pb::ast::STMT_COMMIT_TRANSACTION);
                return;
            }
            case pb::ast::STMT_ROLLBACK_TRANSACTION: {
                status = TransRollbackTxnStmt::resolve_to((cantor::parser::RollbackTxnStmt*)node, stmt.mutable_rollback_txn_stmt());
                stmt.set_type(pb::ast::STMT_ROLLBACK_TRANSACTION);
                return;
            }
            case pb::ast::STMT_PRAGMA_SET: {
                status = TransPragmaStmt::resolve_to((cantor::parser::PragmaSetStmt*)node, stmt.mutable_pragma_set_stmt());
                stmt.set_type(pb::ast::STMT_PRAGMA_SET);
                return;
            }
            case pb::ast::STMT_NEW_PREPARE: {
                status = TransNewPrepareStmt::resolve_to((cantor::parser::NewPrepareStmt*)node, stmt.mutable_new_prepare_stmt());
                stmt.set_type(pb::ast::STMT_NEW_PREPARE);
                return;
            }
            case pb::ast::STMT_EXEC_PREPARE: {
                status = TransExecPrepareStmt::resolve_to((cantor::parser::ExecPrepareStmt*)node, stmt.mutable_exec_prepare_stmt());
                stmt.set_type(pb::ast::STMT_EXEC_PREPARE);
                return;
            }
            case pb::ast::STMT_DEALLOC_PREPARE: {
                status = TransDeallocPrepareStmt::resolve_to((cantor::parser::DeallocPrepareStmt*)node, stmt.mutable_dealloc_prepare_stmt());
                stmt.set_type(pb::ast::STMT_DEALLOC_PREPARE);
                return;
            }
            case pb::ast::STMT_KILL: {
                status = TransKillStmt::resolve_to((cantor::parser::KillStmt*)node, stmt.mutable_kill_stmt());
                stmt.set_type(pb::ast::STMT_KILL);
                return;
            }
            case pb::ast::STMT_CREATE_NAMESPACE: {
                status = TransCreateNamespaceStmt::resolve_to((cantor::parser::CreateNamespaceStmt*)node, stmt.mutable_create_namespace_stmt());
                stmt.set_type(pb::ast::STMT_CREATE_NAMESPACE);
                return;
            }
            case pb::ast::STMT_DROP_NAMESPACE: {
                status = TransDropNamespaceStmt::resolve_to((cantor::parser::DropNamespaceStmt*)node, stmt.mutable_drop_namespace_stmt());
                stmt.set_type(pb::ast::STMT_DROP_NAMESPACE);
                return;
            }
            case pb::ast::STMT_ALTER_NAMESPACE: {
                status = TransAlterNamespaceStmt::resolve_to((cantor::parser::AlterNamespaceStmt*)node, stmt.mutable_alter_namespace_stmt());
                stmt.set_type(pb::ast::STMT_ALTER_NAMESPACE);
                return;
            }
            case pb::ast::STMT_CREATE_USER: {
                status = TransCreateUserStmt::resolve_to((cantor::parser::CreateUserStmt*)node, stmt.mutable_create_user_stmt());
                stmt.set_type(pb::ast::STMT_CREATE_USER);
                return;
            }
            case pb::ast::STMT_DROP_USER: {
                status = TransDropUserStmt::resolve_to((cantor::parser::DropUserStmt*)node, stmt.mutable_drop_user_stmt());
                stmt.set_type(pb::ast::STMT_DROP_USER);
                return;
            }
            case pb::ast::STMT_ALTER_USER: {
                status = TransAlterUserStmt::resolve_to((cantor::parser::AlterUserStmt*)node, stmt.mutable_alter_user_stmt());
                stmt.set_type(pb::ast::STMT_ALTER_USER);
                return;
            }
            case pb::ast::STMT_GRANT: {
                status = TransPrivStmt::resolve_to((cantor::parser::PrivStmt*)node, stmt.mutable_grant_stmt()->mutable_stmt());
                stmt.set_type(pb::ast::STMT_GRANT);
                return;
            }
            case pb::ast::STMT_REVOKE: {
                status = TransPrivStmt::resolve_to((cantor::parser::PrivStmt*)node, stmt.mutable_revoke_stmt()->mutable_stmt());
                stmt.set_type(pb::ast::STMT_REVOKE);
                return;
            }
            case pb::ast::STMT_INSERT: {
                status = TransInsertStmt::resolve_to((cantor::parser::InsertStmt*)node, stmt.mutable_insert_stmt());
                stmt.set_type(pb::ast::STMT_INSERT);
                return;
            }
            case pb::ast::STMT_UPDATE: {
                status = TransUpdateStmt::resolve_to((cantor::parser::UpdateStmt*)node, stmt.mutable_update_stmt());
                stmt.set_type(pb::ast::STMT_UPDATE);
                return;
            }
            case pb::ast::STMT_TRUNCATE: {
                status = TransTruncateStmt::resolve_to((cantor::parser::TruncateStmt*)node, stmt.mutable_truncate_stmt());
                stmt.set_type(pb::ast::STMT_TRUNCATE);
                return;
            }
            case pb::ast::STMT_DELETE: {
                status = TransDeleteStmt::resolve_to((cantor::parser::DeleteStmt*)node, stmt.mutable_delete_stmt());
                stmt.set_type(pb::ast::STMT_DELETE);
                return;
            }
            case pb::ast::STMT_SELECT: {
                status = TransSelectStmt::resolve_to((cantor::parser::SelectStmt*)node, stmt.mutable_select_stmt());
                stmt.set_type(pb::ast::STMT_SELECT);
                return;
            }
            case pb::ast::STMT_UNION: {
                status = TransUnionStmt::resolve_to((cantor::parser::UnionStmt*)node, stmt.mutable_union_stmt());
                stmt.set_type(pb::ast::STMT_UNION);
                return;
            }
            case pb::ast::STMT_CREATE_TABLE: {
                status = TransCreateTableStmt::resolve_to((cantor::parser::CreateTableStmt*)node, stmt.mutable_create_table_stmt());
                stmt.set_type(pb::ast::STMT_CREATE_TABLE);
                return;
            }
            case pb::ast::STMT_DROP_TABLE: {
                status = TransDropTableStmt::resolve_to((cantor::parser::DropTableStmt*)node, stmt.mutable_drop_table_stmt());
                stmt.set_type(pb::ast::STMT_DROP_TABLE);
                return;
            }
            case pb::ast::STMT_CREATE_VIEW: {
                status = TransCreateViewStmt::resolve_to((cantor::parser::CreateViewStmt*)node, stmt.mutable_create_view_stmt());
                stmt.set_type(pb::ast::STMT_CREATE_VIEW);
                return;
            }
            case pb::ast::STMT_DROP_VIEW: {
                status = TransDropViewStmt::resolve_to((cantor::parser::DropViewStmt*)node, stmt.mutable_drop_view_stmt());
                stmt.set_type(pb::ast::STMT_DROP_VIEW);
                return;
            }
            case pb::ast::STMT_CREATE_DATABASE: {
                status = TransCreateDatabaseStmt::resolve_to((cantor::parser::CreateDatabaseStmt*)node, stmt.mutable_create_database_stmt());
                stmt.set_type(pb::ast::STMT_CREATE_DATABASE);
                return;
            }
            case pb::ast::STMT_DROP_DATABASE: {
                status = TransDropDatabaseStmt::resolve_to((cantor::parser::DropDatabaseStmt*)node, stmt.mutable_drop_database_stmt());
                stmt.set_type(pb::ast::STMT_DROP_DATABASE);
                return;
            }
            case pb::ast::STMT_ALTER_TABLE: {
                status = TransAlterTableStmt::resolve_to((cantor::parser::AlterTableStmt*)node, stmt.mutable_alter_table_stmt());
                stmt.set_type(pb::ast::STMT_ALTER_TABLE);
                return;
            }
            case pb::ast::STMT_ALTER_VIEW: {
                status = TransAlterViewStmt::resolve_to((cantor::parser::AlterViewStmt*)node, stmt.mutable_alter_view_stmt());
                stmt.set_type(pb::ast::STMT_ALTER_VIEW);
                return;
            }
            case pb::ast::STMT_EXPLAIN: {
                status = TransExplainStmt::resolve_to((cantor::parser::ExplainStmt*)node, stmt.mutable_explain_stmt());
                stmt.set_type(pb::ast::STMT_EXPLAIN);
                return;
            }
            case pb::ast::STMT_LOAD_DATA: {
                status = TransLoadDataStmt::resolve_to((cantor::parser::LoadDataStmt*)node, stmt.mutable_load_data_stmt());
                stmt.set_type(pb::ast::STMT_LOAD_DATA);
                return;
            }
            case pb::ast::STMT_RESTORE_TABLE: {
                status = TransRestoreTableStmt::resolve_to((cantor::parser::RestoreTableStmt*)node, stmt.mutable_restore_table_stmt());
                stmt.set_type(pb::ast::STMT_RESTORE_TABLE);
                return;
            }
            default:
                status = turbo::data_loss_error("unknown node type");
                break;
        }
    }

    const turbo::Status &TransStmt::check() {
        if (!status.ok()) {
            return status;
        }
        return status;
    }

    turbo::Status TransStmt::resolve_to(turbo::Nonnull<const cantor::parser::StmtNode *> stmt,
                                        turbo::Nonnull<pb::ast::Statement *> proto_node) {
        TransStmt trnas;
        trnas.resolve_ast(stmt);
        auto status = trnas.check();
        if (!status.ok()) {
            return status;
        }
        *proto_node = std::move(trnas.stmt);
        return status;

    }
}  // namespace cantor::transform
